﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClassFolio.Model
{
    public class Role
	{
		#region Работа с ролями

		/// <summary>
		/// Создание новой роли
		/// </summary>
		/// <param name="name">Имя роли</param>
		/// <returns>Новый экземпляр класса Role</returns>
		/// <remarks>Класс роль не имеет открытого конструктора для создания экземпляра класса. Вместо этого
		/// нужно пользоваться статической функцией CreateRole, которая возвращает новый экземпляр класса Role</remarks>
		public static Role CreateRole(string name)
        {
            return RoleGate.ApplyToDb(Role.LogonUser.ID, new Role(0) { Name = name } );
        }
        
		/// <summary>
        /// Загрузка из базы данных роли по ее идентификатору
        /// </summary>
        /// <param name="roleId">Идентификатор роли в базе данных</param>
        /// <returns>Экземпляр класса Role</returns>
		public static Role LoadRole(int roleId)
        {
            return RoleGate.RefreshFromDb(new Role(roleId));
        }
        
		/// <summary>
		/// Удаление роли
		/// </summary>
		/// <param name="role">Экземпляр класса, который нужно удалить</param>
		public static void RemoveRole(Role role)
        {
            RoleGate.RemoveRole(LogonUser.ID, role.ID);
        }
        
		/// <summary>
		/// Проверка существования роли
		/// </summary>
		/// <param name="role">Экземпляр роли</param>
		/// <returns>True - если роль существует, false - если не существует</returns>
		public static bool RoleExist(Role role)
        {
            return RoleGate.RoleExist(role.ID);
        }
        
		/// <summary>
		/// Сохранение измененных значений свойств класса в базе данных
		/// </summary>
		public void ApplyToDb()
        {
            RoleGate.ApplyToDb(LogonUser.ID, this);
        }
        
		/// <summary>
		/// Обновление свойств класса данными из базы данных
		/// </summary>
		public void RefreshFromDb()
        {
            RoleGate.RefreshFromDb(this);
            this._roleAction = RoleGate.GetActionList(this.ID);
		}

		#endregion

		#region Работа с действиями

		/// <summary>
		/// Назначение действия для роли
		/// </summary>
		/// <param name="actionId">Идентификатор действия</param>
		/// <remarks>Идентификатор действия должен быть получен из файла настроек Actions.settings</remarks>
		public void AssignAction(int actionId)
        {
            RoleGate.RoleAssignAction(LogonUser.ID, this._id, actionId);
            this._roleAction = RoleGate.GetActionList(this.ID);
        }
        
		/// <summary>
		/// Удаление назначенного для роли действия
		/// </summary>
		/// <param name="actionId">Идентификатор действия</param>
		/// <remarks>Идентификатор действия должен быть получен из файла настроек Actions.settings</remarks>
		public void RemoveAction(int actionId)
        {
            RoleGate.RoleRemoveAction(LogonUser.ID, this._id, actionId);
            this._roleAction = RoleGate.GetActionList(this.ID);
        }

		/// <summary>
		/// Проверка наличия разрешения на действие у роли
		/// </summary>
		/// <param name="actionId">Идентификатор действия</param>
		/// <returns>True - если действие для роли назначено, false - в ином случае</returns>
		public bool HaveAction(int actionId)
        {
            return _roleAction.Contains(actionId);
		}
		
		#endregion

		#region Properties
		
		/// <summary>
		/// Идентификатор роли в базе данных
		/// </summary>
		public int ID { get { return _id; } }
        
		/// <summary>
		/// Имя роли.
		/// </summary>
		/// <remarks>Имя роли не должно быть пустым и превышать 32 символов. 
		/// Это ограничение автоматически отслеживается 
		/// классом. При присвоении свойству строки большего размера, она автоматически обрезается до указанной
		/// длины.</remarks>
		/// <exception cref="EFolio">При попытке присвоить свойству пустое значение генерируется исключительная
		/// ситуация</exception>
		public string Name 
		{
			get { return this._name; }
			set 
			{ 
				if (String.IsNullOrEmpty(value))
					throw new EFolio(0, MessageType.UserMessage, Messages.rl_empty_name, null);
				else
					this._name = Tools.SubStr(value, 32);
			} 
		}
        
		/// <summary>
		/// Список действий доступных для роли
		/// </summary>
		public List<int> ActionList { get { return _roleAction; } }

		/// <summary>
		/// Шлюз таблицы
		/// </summary>
		public static IRoleGate RoleGate { get; set; }
		
		/// <summary>
		/// Текущий пользователь подключенный к базе
		/// </summary>
		/// <remarks>
		/// Значение свойству присваивается во время инициализации системы функцией 
		/// <see cref="LoginAs"/> класса <see cref="GeneFolio.AreaWork.AreaWork"/>
		/// </remarks>
		public static User LogonUser { get; set; }

		#endregion

		#region Private
		
		private Role(int roleId)
        {
            this._id = roleId;
        }
        private int _id = 0;
		private string _name;
        private List<int> _roleAction = new List<int>();
		
		#endregion
	}

    public interface IRoleGate
    {
        void RemoveRole(int activeUserId, int roleId);
        Role ApplyToDb(int activeUserId, Role role);
        Role RefreshFromDb(Role role);
        bool RoleExist(int roleId);

        List<int> GetActionList(int roleId);
        void RoleAssignAction(int activeUserId, int roleId, int actionId);
        void RoleAssignActionInherit(int activeUserId, int roleId, int actionId);
        void RoleRemoveAction(int activeUserId, int roleId, int actionId);
    }

}

